package com.wdb.modules.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wdb.exception.BadRequestException;
import com.wdb.exception.EntityExistException;
import com.wdb.modules.security.service.dto.AuthorityDto;
import com.wdb.modules.system.domain.Menu;
import com.wdb.modules.system.domain.Role;
import com.wdb.modules.system.domain.User;
import com.wdb.modules.system.domain.dto.RoleExcelDTO;
import com.wdb.modules.system.domain.vo.RoleQueryCriteria;
import com.wdb.modules.system.mapper.RoleDeptMapper;
import com.wdb.modules.system.mapper.RoleMapper;
import com.wdb.modules.system.mapper.RoleMenuMapper;
import com.wdb.modules.system.mapper.UserMapper;
import com.wdb.modules.system.service.RoleService;
import com.wdb.utils.FileUtil;
import com.wdb.utils.PageResult;
import com.wdb.utils.PageUtil;
import com.wdb.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: wendaobai@qq.com
 * @date: 2024/1/18 0018 16:02
 */
@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = "role")
@Slf4j
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {
  private final RoleMapper roleMapper;
  private final RoleDeptMapper roleDeptMapper;
  private final UserMapper userMapper;
  private final RoleMenuMapper roleMenuMapper;

  @Override
  public List<AuthorityDto> mapToGrantedAuthorities(User user) {
    Set<String> permissions = new HashSet<>();
    // 如果是管理员直接返回
    if (user.getIsAdmin()) {
      permissions.add("admin");
      return permissions.stream().map(AuthorityDto::new).collect(Collectors.toList());
    }

    List<Role> roles = roleMapper.findByUserId(user.getId());
    permissions =
        roles.stream()
            .flatMap(role -> role.getMenus().stream())
            .map(Menu::getPermission)
            .filter(StringUtils::isNotBlank)
            .collect(Collectors.toSet());
    return permissions.stream().map(AuthorityDto::new).collect(Collectors.toList());
  }

  @Override
  public List<Role> findByUsersId(Long id) {
    return roleMapper.findByUserId(id);
  }

  @Override
  public PageResult<Role> queryAll(RoleQueryCriteria criteria, Page<Object> page) {
    criteria.setOffset(page.offset());
    List<Role> roles = roleMapper.findAll(criteria);
    Integer total = roleMapper.countAll(criteria);
    return PageUtil.toPage(roles, total);
  }

  @Override
  public List<Role> queryAll(RoleQueryCriteria criteria) {
    return roleMapper.findAll(criteria);
  }

  @Override
  public void download(List<Role> roleList, HttpServletResponse response) throws IOException {
    ArrayList<Map<String, Object>> list = new ArrayList<>();
    for (Role role : roleList) {
      Map<String, Object> map = new HashMap<>();
      map.put("角色名称", role.getName());
      map.put("角色级别", role.getLevel());
      map.put("描述", role.getDescription());
      map.put("创建日期", role.getCreateTime());
      list.add(map);
    }
    FileUtil.downloadExcel(list, response);
  }

  @Override
  public void easyDownload(List<Role> roleList, HttpServletResponse response) throws Exception {
    ArrayList<RoleExcelDTO> excelDTOArrayList = new ArrayList<>();
    for (Role role : roleList) {
      RoleExcelDTO roleExcelDTO = new RoleExcelDTO();
      roleExcelDTO.setName(role.getName());
      roleExcelDTO.setDescription(role.getDescription());
      DateTime dateTime = new DateTime(role.getCreateTime());
      roleExcelDTO.setCreateTime(dateTime.toString());
      roleExcelDTO.setLevel(role.getLevel().toString());
      excelDTOArrayList.add(roleExcelDTO);
    }
    // 这里注意 有同学反应使用swagger 会导致各种问题，请直接用浏览器或者用postman
    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    response.setCharacterEncoding("utf-8");
    // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
    String fileName = URLEncoder.encode("角色列表", "UTF-8").replaceAll("\\+", "%20");
    response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
    EasyExcel.write(response.getOutputStream(), RoleExcelDTO.class)
        .sheet("模板11")
        .doWrite(excelDTOArrayList);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void create(Role role) {
    // 判断role名称是否存在
    QueryWrapper<Role> roleQueryWrapper = new QueryWrapper<>();
    roleQueryWrapper.lambda().eq(Role::getName, role.getName());
    List<Role> roleList = roleMapper.selectList(roleQueryWrapper);
    log.info("loginfo:{}", roleList);
    if (roleList.size() > 0) {
      throw new EntityExistException(Role.class, "username", role.getName());
    }
    // 插入数据
    this.save(role);
    // 判断是否有部门数据，若有，则需创建关联
    if (CollectionUtil.isNotEmpty(role.getDepts())) {
      roleDeptMapper.insertData(role.getId(), role.getDepts());
    }
  }

  @Override
  public void verification(List<Integer> ids) {

    int count = userMapper.countByRoles(ids);
    if (count > 0) {
      throw new BadRequestException("所选角色存在用户关联，请解除关联再试！");
    }
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void delete(List<Integer> ids) {
    // 缓存清除
    this.removeBatchByIds(ids);
    // 删除 角色菜单
    roleDeptMapper.deleteByRoleIds(ids);
    // 删除 dept关联数据
    roleMenuMapper.deleteByRoleIds(ids);
  }
}
